package com.qianya.system.manage.config;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.geo.Circle;
import org.springframework.data.geo.Distance;
import org.springframework.data.geo.GeoResults;
import org.springframework.data.geo.Point;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.core.GeoOperations;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;

import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @Author: lhl
 * @Description:
 * @Date: Created in 6.8 2020/6/10
 * @Modifired by:
 */
public class RedisUtil {
    private static final Logger logger = LoggerFactory.getLogger(RedisUtil.class);

    static private RedisTemplate redisTemplate;
    static private  RedisTemplate getRedisTemplate() {
        if (redisTemplate == null) {
            redisTemplate = ApplicationContextHolder.getBean("redisTemplate");
        }
//        RedisSerializer stringSerializer = new StringRedisSerializer();//序列化为String
//        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);//序列化为Json
//        redisTemplate.setKeySerializer(stringSerializer);
//        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
//        redisTemplate.setHashKeySerializer(stringSerializer);
//        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
        return redisTemplate;
    }

    /**
     * Clears this cache instance
     */
    public static void clear() {
        RedisTemplate redisTemplate = getRedisTemplate();
        redisTemplate.execute((RedisCallback) connection -> {
            connection.flushDb();
            return null;
        });
    }
    /**
     * 删除锁
     *
     * @param key
     */
    public void delete(String key) {
        redisTemplate.delete(key);
    }
    /**
     * 根据key 获取过期时间
     * @param key 键 不能为null
     * @return 时间(秒) 返回0代表为永久有效
     */
    public long getExpire(String key){
        return redisTemplate.getExpire(key,TimeUnit.SECONDS);
    }
    /**
     * 指定缓存失效时间
     * @param key 键
     * @param time 时间(秒)
     * @return
     */
    public boolean expire(String key,long time){
        try {
            if(time>0){
                redisTemplate.expire(key, time, TimeUnit.SECONDS);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 递增
     * @param key 键
     * @return
     */
    public long incr(String key, long delta){
        if(delta<0){
            throw new RuntimeException("递增因子必须大于0");
        }
        return redisTemplate.opsForValue().increment(key, delta);
    }
    /**
     * 递减
     * @param key 键
     * @return
     */
    public long decr(String key, long delta){
        if(delta<0){
            throw new RuntimeException("递减因子必须大于0");
        }
        return redisTemplate.opsForValue().increment(key, -delta);
    }
    /**
     * Remove cached query result from redis
     *
     * @param key
     * @return
     */
    @SuppressWarnings("unchecked")
    public static Object removeObject(Object key) {
        try {
            RedisTemplate redisTemplate = getRedisTemplate();
            redisTemplate.delete(key);
            logger.debug("Remove cached query result from redis");
        }
        catch (Throwable t) {
            logger.error("Redis remove failed", t);
        }
        return null;
    }


    /**
     * Put query result to redis
     *
     * @param key
     * @param value
     */
    @SuppressWarnings("unchecked")
    public static void putObject(Object key, Object value, long EXPIRE_TIME, TimeUnit timeUnit) {
        try {
            RedisTemplate redisTemplate = getRedisTemplate();
            ValueOperations opsForValue = redisTemplate.opsForValue();
            opsForValue.set(key, value, EXPIRE_TIME, timeUnit);
            logger.debug("Put query result to redis");
        }
        catch (Throwable t) {
            logger.error("Redis put failed", t);
        }
    }

    /**
     * Put geo result to redis
     *
     * @param key
     * @param m
     */
    @SuppressWarnings("unchecked")
    public static Long geoAdd(Object key, Point point, Object m) {
        try {
            RedisTemplate redisTemplate = getRedisTemplate();
            GeoOperations geoValue = redisTemplate.opsForGeo();
            logger.debug("geoAdd result to redis");
            return geoValue.geoAdd(key,point,m);

        }
        catch (Throwable t) {
            logger.error("geoAdd failed", t);
        }
        return null;
    }

    /**
     * geo dist result to redis
     *
     * @param key
     * @param m1,m2
     */
    @SuppressWarnings("unchecked")
    public static Distance geoDist(Object key, Object m1, Object m2) {
        try {
            RedisTemplate redisTemplate = getRedisTemplate();
            GeoOperations geoValue = redisTemplate.opsForGeo();
            logger.debug("geoAdd result to redis");
            return  geoValue.geoDist(key,m1,m1);
        }
        catch (Throwable t) {
            logger.error("geoAdd failed", t);
        }
        return null;
    }

    /**
     * nearDist
     * @param key
     * @param circle
     * @param args
     * @return
     */
    public static GeoResults<RedisGeoCommands.GeoLocation> nearDist(Object key, Circle circle, RedisGeoCommands.GeoRadiusCommandArgs args) {
        try {
            RedisTemplate redisTemplate = getRedisTemplate();
            GeoOperations geoValue = redisTemplate.opsForGeo();
            logger.debug("geoAdd result to redis");
            return  geoValue.geoRadius(key,circle,args);
        }
        catch (Throwable t) {
            logger.error("geoAdd failed", t);
        }
        return null;
    }



    public static double zscore(String key, Object member) {
        double value = 0;
        RedisTemplate redisTemplate = getRedisTemplate();
        value = redisTemplate.opsForZSet().score(key,member);
        return value;
    }

    /***
     * <p>
     * Description: 得到值
     * </p>
     *
     * @param key
     */
    public static Object get(String key) {
        Object value = null;
        RedisTemplate redisTemplate = getRedisTemplate();
        value = redisTemplate.opsForValue().get(key);
        return value;
    }

    /***
     * <p>
     * Description: 设置键值
     * </p>
     * @param key
     *            value
     */
    public static void set(String key, Object value) {
        RedisTemplate redisTemplate = getRedisTemplate();
        redisTemplate.opsForValue().set(key,value);
    }
    /***
     * <p>
     * Description: 设置键值并设置过期时间
     * </p>
     * @param key
     *            value
     */
    public static void set(String key, Object value,long expairTime) {
        RedisTemplate redisTemplate = getRedisTemplate();
        redisTemplate.opsForValue().set(key,value,expairTime,TimeUnit.SECONDS);
    }
    /***
     * <p>
     * Description: 设置键值 并同时设置有效期
     * </p>
     * @param key
     *            seconds秒数 value
     */
    public static void setex(String key, String value) {
        RedisTemplate redisTemplate = getRedisTemplate();
        redisTemplate.opsForValue().setIfAbsent(key,value);
    }

    /**
     *判断redis中是否已存在key对应的value
     * @param key
     * @return true/false
     *
     */
    public static boolean isExistValue(String key){
        if (StringUtils.isBlank(key)){
            return false;
        }

        // 根据key获取redis的value
        RedisTemplate redisTemplate = getRedisTemplate();
        Object value = redisTemplate.opsForValue().get(key);

        if (value == null){
            return false;
        }
        return true;
    }

    /**
     *判断redis中是否已存在key
     * @param key
     * @return true/false
     *
     */
    public static boolean isExistKey(String key){
        if (StringUtils.isBlank(key)){
            return false;
        }
        RedisTemplate redisTemplate = getRedisTemplate();
        return redisTemplate.hasKey(key);

    }
    /*添加list
     * @param mapName
     * @return void
     *
     */
    public static void lset(String key, Object obj){
        RedisTemplate redisTemplate = getRedisTemplate();
        redisTemplate.opsForList().leftPush(key,obj);
    }
    /**
     *获得list
     * @param key
     * @return Object
     *
     */
    public static Object lget(String key,long begin,long end){
        RedisTemplate redisTemplate = getRedisTemplate();
        return redisTemplate.opsForList().range(key, begin, end);
    }
    /**
     *添加hash
     * @param mapName
     * @return void
     *
     */
    public static void hset(String mapName,Map<String,Object> map){
        RedisTemplate redisTemplate = getRedisTemplate();
        redisTemplate.opsForHash().putAll(mapName,map);
    }
    /**
     *获得hash
     * @param mapName
     * @param key
     * @return Object
     *
     */
    public static Object hget(String mapName,String key){
        RedisTemplate redisTemplate = getRedisTemplate();
        if (key.equals("")){
            return redisTemplate.opsForHash().entries(mapName);
        }
        return redisTemplate.opsForHash().get(mapName,key);
    }
}